package com.dsteiner.xelavos.client.controller;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Date;

import com.dsteiner.widgets.client.DateUtilImpl;
import com.dsteiner.widgets.client.IJsUtil;
import com.dsteiner.widgets.client.JsUtil;
import com.dsteiner.widgets.client.StringUtil;
import com.dsteiner.widgets.client.Widgets.IHTML;
import com.dsteiner.widgets.client.Widgets.IImage;
import com.dsteiner.widgets.client.Widgets.ILazyWidget;
import com.dsteiner.widgets.client.Widgets.IWidget;
import com.dsteiner.widgets.client.Widgets.WidgetListenerAdapter;
import com.dsteiner.widgets.client.controller.PopupOverlayController;
import com.dsteiner.widgets.client.domain.ModelObject;
import com.dsteiner.widgets.client.event.DataUpdateEvent;
import com.dsteiner.widgets.client.event.Event;
import com.dsteiner.widgets.client.event.EventListener;
import com.dsteiner.widgets.client.event.EventManager;
import com.dsteiner.widgets.client.event.EventManagerImpl;
import com.dsteiner.widgets.client.model.PopupOverlayModel;
import com.dsteiner.widgets.client.rpc.CrudResult;
import com.dsteiner.xelavos.client.constants.Constants;
import com.dsteiner.xelavos.client.domain.Comment;
import com.dsteiner.xelavos.client.domain.Rateable;
import com.dsteiner.xelavos.client.domain.Rating;
import com.dsteiner.xelavos.client.domain.User;
import com.dsteiner.xelavos.client.model.AuthenticationModel;
import com.dsteiner.xelavos.client.model.CommentModel;
import com.dsteiner.xelavos.client.model.DisplayModel;
import com.dsteiner.xelavos.client.rpc.DataService;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class CommentController {

	private CommentModel commentModel;
	private IHTML userHtml;
	private IHTML commentMessageHtml;
	private IHTML registeredDateHtml;
	private IHTML ratingHtml;
	private IHTML messageHtml;
	private AuthenticationModel authenticationModel;
	private DisplayModel userDisplayModel;
	private PopupOverlayModel userPopupOverlayModel;
	private IJsUtil jsUtil;

	public void registerAuthenticationModel(AuthenticationModel authenticationModel) {
		this.authenticationModel = authenticationModel;
	}

	public void registerCommentMessageHtml(IHTML messageHtml) {
		this.commentMessageHtml = messageHtml;
	}

	public void registerCommentModel(CommentModel commentModel) {
		this.commentModel = commentModel;
		commentModel.addPropertyChangeListener("modelObject", new PropertyChangeListener(){
			public void propertyChange(PropertyChangeEvent evt) {
				updateComment();
				updateMessage();
			}
		});
		commentModel.addPropertyChangeListener("message", new PropertyChangeListener(){
			public void propertyChange(PropertyChangeEvent evt) {
				updateMessage();
			}
		});
	}

	public void registerCommentWidget(ILazyWidget commentWidget) {
		commentWidget.addWidgetListener(new WidgetListenerAdapter() {
			@Override
			public void onAttach(IWidget widget) {
				updateComment();
				updateMessage();
			}
		});
	}

	public void registerEventManager(EventManager eventManager) {
		eventManager.registerListener(DataUpdateEvent.class, new EventListener(){
			public void onEvent(Event event) {
				DataUpdateEvent dataUpdateEvent = (DataUpdateEvent) event;
				if(dataUpdateEvent.getObject() instanceof Comment){
					updateComment();
				}
			}
		});
	}

	public void registerMessageHtml(IHTML messageHtml) {
		this.messageHtml = messageHtml;
	}

	public void registerRatingDownIcon(IImage ratingDownIcon) {
		ratingDownIcon.addClickHandler(new ClickHandler(){
			public void onClick(ClickEvent event) {
				doAddRating(-1);
				jsUtil.trackEvent(Constants.CAT_COMMENT, Constants.ACT_RATE_UP);
			}
		});
	}

	public void registerRatingHtml(IHTML ratingHtml) {
		this.ratingHtml = ratingHtml;
	}

	public void registerRatingUpIcon(IImage ratingUpIcon) {
		ratingUpIcon.addClickHandler(new ClickHandler(){
			public void onClick(ClickEvent event) {
				doAddRating(1);
				jsUtil.trackEvent(Constants.CAT_COMMENT, Constants.ACT_RATE_DOWN);
			}
		});
	}
	
	public void registerRegisteredDateHtml(IHTML registeredDateHtml) {
		this.registeredDateHtml = registeredDateHtml;
	}

	public void registerUserHtml(IHTML userHtml) {
		this.userHtml = userHtml;
		userHtml.addClickHandler(new ClickHandler(){
			public void onClick(ClickEvent event) {
				jsUtil.trackEvent(Constants.CAT_COMMENT, Constants.ACT_CLICKED_USER_LINK);
				Comment comment = (Comment) commentModel.getModelObject();
				DataService.Util.getInstance().getObjectById(comment.getUserId(), 
						User.class.getName(), new AsyncCallback<CrudResult<ModelObject>>(){
					public void onFailure(Throwable caught) {
						caught.printStackTrace();
					}
					public void onSuccess(CrudResult result) {
						PopupOverlayController.showAtCenter(userPopupOverlayModel);
						userDisplayModel.setModelObject(result.getModelObject());
					}
				});
			}
		});
	}

	private void doAddRating(final int rating) {
		final ModelObject modelObject = commentModel.getModelObject();
		User user = authenticationModel.getUser();
		if(user == null){
			JsUtil.getInstance().showAlert("necesita estar logeado para clasificar");
			return;
		}
		
		boolean alreadyRated = authenticationModel.isAlreadyRated(modelObject.getId());
		if(alreadyRated){
			commentModel.setMessage(Constants.MSG_OBJ_ALREADY_RATED);
			return;
		}
		
		final Rating ratingObj = new Rating();
		ratingObj.setUserId(user.getId());
		ratingObj.setRating(rating);
		ratingObj.setRefId(modelObject.getId());
		ratingObj.setRefClass(modelObject.getClass().getName());
		ratingObj.setRegisteredDate(new Date());
		DataService.Util.getInstance().createModelObject(ratingObj, new AsyncCallback<CrudResult<ModelObject>>(){
			public void onFailure(Throwable caught) {
				caught.printStackTrace();
			}
			public void onSuccess(CrudResult result) {
				authenticationModel.addRating(ratingObj);
				if(Constants.MSG_OBJ_ALREADY_RATED.equals(result.getError())){
					commentModel.setMessage(Constants.MSG_OBJ_ALREADY_RATED);
				}
				else{
					((Rateable)modelObject).addRating(rating);
					EventManagerImpl.getInstance().fireEvent(new DataUpdateEvent(modelObject));
				}
			}
		});
	}

	private void updateComment() {
		Comment comment = (Comment) commentModel.getModelObject();
		userHtml.setHTML("<a href=\"javascript:void(0);\">"+comment.getUserFirstName()+"</a>");
		commentMessageHtml.setHTML(StringUtil.toHtml(comment.getMessage()));
		Date registeredDate = comment.getRegisteredDate();
		String timePassedSince = DateUtilImpl.formatDatePassedSince(registeredDate);
		registeredDateHtml.setHTML("("+timePassedSince+")");
		
		int rating = comment.getRating();
		String ratingString = rating+"";
		if(rating > 0)
			ratingString = "+"+rating;
		ratingHtml.setHTML(ratingString);
	}

	private void updateMessage() {
		String message = commentModel.getMessage();
		messageHtml.setVisible(message != null);
		messageHtml.setHTML(message);
	}

	public void registerUserDisplayModel(DisplayModel userDisplayModel) {
		this.userDisplayModel = userDisplayModel;
	}

	public void registerUserPopupOverlayModel(PopupOverlayModel userPopupOverlayModel) {
		this.userPopupOverlayModel = userPopupOverlayModel;
	}

	public void registerJsUtil(IJsUtil jsUtil) {
		this.jsUtil = jsUtil;
	}
}